/*
 * 描          述:  <描述>
 * 修  改   人:  
 * 修改时间:  
 * <修改描述:>
 */
package com.tx.component.attachment.service;

import java.beans.PropertyDescriptor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.persistence.Column;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.transaction.annotation.Transactional;

import com.tx.component.attachment.dao.AttachmentTagDao;
import com.tx.component.attachment.model.AttachmentTag;
import com.tx.core.exceptions.util.AssertUtils;
import com.tx.core.paged.model.PagedList;
import com.tx.core.querier.model.Querier;
import com.tx.core.querier.model.QuerierBuilder;

/**
 * AttachmentTag的业务层[AttachmentTagService]
 * <功能详细描述>
 * 
 * @author  
 * @version [版本号]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class AttachmentTagService {
    
    @SuppressWarnings("unused")
    private Logger logger = LoggerFactory.getLogger(AttachmentTagService.class);
    
    private AttachmentTagDao attachmentTagDao;
    
    /** <默认构造函数> */
    public AttachmentTagService() {
        super();
    }
    
    /** <默认构造函数> */
    public AttachmentTagService(AttachmentTagDao attachmentTagDao) {
        super();
        this.attachmentTagDao = attachmentTagDao;
    }
    
    /**
     * 批量保存<br/>
     * <功能详细描述>
     * @param items [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @Transactional
    public void batchSave(String attachmentId, List<AttachmentTag> tags) {
        if (CollectionUtils.isEmpty(tags)) {
            return;
        }
        AssertUtils.notEmpty(attachmentId, "attachmentId is empty.");
        
        Map<String, Object> params = new HashMap<>();
        params.put("attachmentId", attachmentId);
        List<AttachmentTag> dbItems = this.attachmentTagDao.queryList(params);
        Map<String, AttachmentTag> dbItemMap = dbItems.stream()
                .collect(Collectors.toMap(item -> item.getId(), item -> item));
        Map<String, AttachmentTag> saveItemMap = tags.stream()
                .filter(t -> !StringUtils.isEmpty(t.getId()))
                .collect(Collectors.toMap(item -> item.getId(), item -> item));
        
        //批量删除
        batchDelete(dbItems.stream()
                .filter(t -> !saveItemMap.containsKey(t.getId()))
                .collect(Collectors.toList()));
        //批量新增
        batchInsert(tags.stream()
                .filter(t -> (StringUtils.isEmpty(t.getId())
                        || !dbItemMap.containsKey(t.getId())))
                .collect(Collectors.toList()));
        //批量更新(暂使用暴力全更新，如需要后期再进行判断后更新)
        batchUpdate(tags.stream().filter(t -> {
            if (!StringUtils.isEmpty(t.getId())
                    && dbItemMap.containsKey(t.getId())) {
                if (!StringUtils.equals(t.getText(),
                        dbItemMap.get(t.getId()).getText())) {
                    return true;
                }
            }
            return false;
        }).collect(Collectors.toList()));
    }
    
    /**
     * 批量插入<br/>
     * <功能详细描述>
     * @param items [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @Transactional
    public void batchInsert(List<AttachmentTag> tags) {
        if (CollectionUtils.isEmpty(tags)) {
            return;
        }
        tags.forEach(item -> {
            AssertUtils.notNull(item, "attachmentTag is null.");
            
            AssertUtils.notEmpty(item.getAttachmentId(),
                    "attachmentTag.attachmentId is empty.");
            AssertUtils.notEmpty(item.getName(),
                    "attachmentTag.name is empty.");
            AssertUtils.notEmpty(item.getText(),
                    "attachmentTag.text is empty.");
        });
        this.attachmentTagDao.batchInsert(tags);
    }
    
    /**
     * 批量删除<br/>
     * <功能详细描述>
     * @param items [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @Transactional
    public void batchDelete(List<AttachmentTag> tags) {
        if (CollectionUtils.isEmpty(tags)) {
            return;
        }
        this.attachmentTagDao.batchDelete(tags);
    }
    
    /**
     * 批量更新
     * <功能详细描述>
     * @param items [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @Transactional
    public void batchUpdate(List<AttachmentTag> tags) {
        if (CollectionUtils.isEmpty(tags)) {
            return;
        }
        
        List<Map<String, Object>> rows = tags.stream().map(item -> {
            AssertUtils.notEmpty(item.getId(), "attachmentTag.id is empty.");
            
            AssertUtils.notEmpty(item.getText(),
                    "attachmentTag.text is empty.");
            
            Map<String, Object> updateRowMap = new HashMap<String, Object>();
            //需要更新的字段
            updateRowMap.put("id", item.getId());
            //批量更新的字段
            updateRowMap.put("text", item.getText());
            return updateRowMap;
        }).collect(Collectors.toList());
        this.attachmentTagDao.batchUpdate(rows);
    }
    
    /**
     * 新增AttachmentTag实例<br/>
     * 将attachmentTag插入数据库中保存
     * 1、如果attachmentTag 为空时抛出参数为空异常
     * 2、如果attachmentTag 中部分必要参数为非法值时抛出参数不合法异常
     * 
     * @param attachmentTag [参数说明]
     * @return void [返回类型说明]
     * @exception throws
     * @see [类、类#方法、类#成员]
     */
    @Transactional
    public void insert(AttachmentTag attachmentTag) {
        //验证参数是否合法
        AssertUtils.notNull(attachmentTag, "attachmentTag is null.");
        AssertUtils.notEmpty(attachmentTag.getName(),
                "attachmentTag.name is empty.");
        AssertUtils.notEmpty(attachmentTag.getAttachmentId(),
                "attachmentTag.attachmentId is empty.");
        
        //调用数据持久层对实例进行持久化操作
        this.attachmentTagDao.insert(attachmentTag);
    }
    
    /**
     * 根据id删除AttachmentTag实例
     * 1、如果入参数为空，则抛出异常
     * 2、执行删除后，将返回数据库中被影响的条数 > 0，则返回true
     *
     * @param id
     * @return boolean 删除的条数>0则为true [返回类型说明]
     * @exception throws 
     * @see [类、类#方法、类#成员]
     */
    @Transactional
    public boolean deleteById(String id) {
        AssertUtils.notEmpty(id, "id is empty.");
        
        AttachmentTag condition = new AttachmentTag();
        condition.setId(id);
        
        int resInt = this.attachmentTagDao.delete(condition);
        boolean flag = resInt > 0;
        return flag;
    }
    
    /**
     * 根据id删除AttachmentTag实例
     * 1、如果入参数为空，则抛出异常
     * 2、执行删除后，将返回数据库中被影响的条数 > 0，则返回true
     *
     * @param id
     * @return boolean 删除的条数>0则为true [返回类型说明]
     * @exception throws 
     * @see [类、类#方法、类#成员]
     */
    @Transactional
    public boolean deleteByAttachmentId(String attachmentId) {
        AssertUtils.notEmpty(attachmentId, "attachmentId is empty.");
        
        AttachmentTag condition = new AttachmentTag();
        condition.setAttachmentId(attachmentId);
        
        this.attachmentTagDao.delete(condition);
        //这里就不再判断删除了多少条了，避免没有关联的tag
        return true;
    }
    
    /**
     * 根据id查询AttachmentTag实例
     * 1、当id为empty时抛出异常
     *
     * @param id
     * @return AttachmentTag [返回类型说明]
     * @exception throws
     * @see [类、类#方法、类#成员]
     */
    public AttachmentTag findById(String id) {
        AssertUtils.notEmpty(id, "id is empty.");
        
        AttachmentTag condition = new AttachmentTag();
        condition.setId(id);
        
        AttachmentTag res = this.attachmentTagDao.find(condition);
        return res;
    }
    
    /**
     * 查询AttachmentTag实例列表
     * <功能详细描述>
     * @param params      
     * @return [参数说明]
     * 
     * @return List<AttachmentTag> [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public List<AttachmentTag> queryListByAttachmentId(String attachmentId,
            Map<String, Object> params) {
        //生成查询条件
        params = params == null ? new HashMap<String, Object>() : params;
        params.put("attachmentId", attachmentId);
        
        //根据实际情况，填入排序字段等条件，根据是否需要排序，选择调用dao内方法
        List<AttachmentTag> resList = this.attachmentTagDao.queryList(params);
        
        return resList;
    }
    
    /**
     * 查询AttachmentTag实例列表
     * <功能详细描述>
     * @param params      
     * @return [参数说明]
     * 
     * @return List<AttachmentTag> [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public List<AttachmentTag> queryList(Map<String, Object> params) {
        //生成查询条件
        params = params == null ? new HashMap<String, Object>() : params;
        
        //根据实际情况，填入排序字段等条件，根据是否需要排序，选择调用dao内方法
        List<AttachmentTag> resList = this.attachmentTagDao.queryList(params);
        
        return resList;
    }
    
    /**
     * 查询AttachmentTag实例列表
     * <功能详细描述>
     * @param querier      
     * @return [参数说明]
     * 
     * @return List<AttachmentTag> [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public List<AttachmentTag> queryList(Querier querier) {
        //生成查询条件
        querier = querier == null ? QuerierBuilder.newInstance().querier()
                : querier;
        
        //根据实际情况，填入排序字段等条件，根据是否需要排序，选择调用dao内方法
        List<AttachmentTag> resList = this.attachmentTagDao.queryList(querier);
        
        return resList;
    }
    
    /**
     * 分页查询AttachmentTag实例列表
     * <功能详细描述>
     * @param params    
     * @param pageIndex 当前页index从1开始计算
     * @param pageSize 每页显示行数
     * 
     * <功能详细描述>
     * @return [参数说明]
     * 
     * @return List<AttachmentTag> [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public PagedList<AttachmentTag> queryPagedList(Map<String, Object> params,
            int pageIndex, int pageSize) {
        //生成查询条件
        params = params == null ? new HashMap<String, Object>() : params;
        
        //根据实际情况，填入排序字段等条件，根据是否需要排序，选择调用dao内方法
        PagedList<AttachmentTag> resPagedList = this.attachmentTagDao
                .queryPagedList(params, pageIndex, pageSize);
        
        return resPagedList;
    }
    
    /**
     * 分页查询AttachmentTag实例列表
     * <功能详细描述>
     * @param querier    
     * @param pageIndex 当前页index从1开始计算
     * @param pageSize 每页显示行数
     * 
     * <功能详细描述>
     * @return [参数说明]
     * 
     * @return List<AttachmentTag> [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public PagedList<AttachmentTag> queryPagedList(Querier querier,
            int pageIndex, int pageSize) {
        //生成查询条件
        querier = querier == null ? QuerierBuilder.newInstance().querier()
                : querier;
        
        //根据实际情况，填入排序字段等条件，根据是否需要排序，选择调用dao内方法
        PagedList<AttachmentTag> resPagedList = this.attachmentTagDao
                .queryPagedList(querier, pageIndex, pageSize);
        
        return resPagedList;
    }
    
    /**
     * 查询AttachmentTag实例数量<br/>
     * <功能详细描述>
     * @param params      
     * @return [参数说明]
     * 
     * @return List<AttachmentTag> [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public int count(Map<String, Object> params) {
        //生成查询条件
        params = params == null ? new HashMap<String, Object>() : params;
        
        //根据实际情况，填入排序字段等条件，根据是否需要排序，选择调用dao内方法
        int res = this.attachmentTagDao.count(params);
        
        return res;
    }
    
    /**
     * 查询AttachmentTag实例数量<br/>
     * <功能详细描述>
     * @param querier      
     * @return [参数说明]
     * 
     * @return List<AttachmentTag> [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public int count(Querier querier) {
        //生成查询条件
        querier = querier == null ? QuerierBuilder.newInstance().querier()
                : querier;
        
        //根据实际情况，填入排序字段等条件，根据是否需要排序，选择调用dao内方法
        int res = this.attachmentTagDao.count(querier);
        
        return res;
    }
    
    /**
     * 判断AttachmentTag实例是否已经存在<br/>
     * <功能详细描述>
     * @param key2valueMap
     * @param excludeId
     * @return
     * 
     * @return int [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public boolean exists(Map<String, String> key2valueMap, String excludeId) {
        AssertUtils.notEmpty(key2valueMap, "key2valueMap is empty");
        
        //生成查询条件
        Map<String, Object> params = new HashMap<String, Object>();
        params.putAll(key2valueMap);
        
        //根据实际情况，填入排序字段等条件，根据是否需要排序，选择调用dao内方法
        int res = this.attachmentTagDao.count(params, excludeId);
        
        return res > 0;
    }
    
    /**
     * 判断AttachmentTag实例是否已经存在<br/>
     * <功能详细描述>
     * @param key2valueMap
     * @param excludeId
     * @return
     * 
     * @return int [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public boolean exists(Querier querier, String excludeId) {
        AssertUtils.notNull(querier, "querier is null.");
        
        //根据实际情况，填入排序字段等条件，根据是否需要排序，选择调用dao内方法
        int res = this.attachmentTagDao.count(querier, excludeId);
        
        return res > 0;
    }
    
    /**
     * 根据id更新AttachmentTag实例<br/>
     * <功能详细描述>
     * @param attachmentTag
     * @return [参数说明]
     * 
     * @return boolean [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @Transactional
    public boolean updateById(String id, Map<String, Object> updateRowMap) {
        //验证参数是否合法，必填字段是否填写
        AssertUtils.notEmpty(id, "id is empty.");
        AssertUtils.notEmpty(updateRowMap, "updateRowMap is empty.");
        
        boolean flag = this.attachmentTagDao.update(id, updateRowMap);
        //如果需要大于1时，抛出异常并回滚，需要在这里修改
        return flag;
    }
    
    /**
     * 根据id更新AttachmentTag实例<br/>
     * <功能详细描述>
     * @param attachmentTag
     * @return [参数说明]
     * 
     * @return boolean [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @Transactional
    public boolean updateById(String id, AttachmentTag attachmentTag) {
        //验证参数是否合法，必填字段是否填写
        AssertUtils.notNull(attachmentTag, "attachmentTag is null.");
        AssertUtils.notEmpty(id, "id is empty.");
        
        //生成需要更新字段的hashMap
        Map<String, Object> updateRowMap = new HashMap<String, Object>();
        //需要更新的字段
        //updateRowMap.put("name", attachmentTag.getName());
        //updateRowMap.put("attachmentId", attachmentTag.getAttachmentId());
        updateRowMap.put("text", attachmentTag.getText());
        
        boolean flag = this.attachmentTagDao.update(id, updateRowMap);
        //如果需要大于1时，抛出异常并回滚，需要在这里修改
        return flag;
    }
    
    /**
     * 根据id更新AttachmentTag实例<br/>
     * <功能详细描述>
     * @param attachmentTag
     * @return [参数说明]
     * 
     * @return boolean [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @Transactional
    public boolean updateById(AttachmentTag attachmentTag) {
        //验证参数是否合法，必填字段是否填写
        AssertUtils.notNull(attachmentTag, "attachmentTag is null.");
        AssertUtils.notEmpty(attachmentTag.getId(),
                "attachmentTag.id is empty.");
        
        Map<String, Object> updateRowMap = new HashMap<String, Object>();
        BeanWrapper bw = PropertyAccessorFactory
                .forBeanPropertyAccess(attachmentTag);
        for (PropertyDescriptor pd : bw.getPropertyDescriptors()) {
            if (pd.getWriteMethod() == null || pd.getReadMethod() == null) {
                continue;
            }
            if ("id".equals(pd.getName())) {
                continue;
            }
            TypeDescriptor td1 = bw.getPropertyTypeDescriptor(pd.getName());
            if (td1.hasAnnotation(Column.class)
                    && !td1.getAnnotation(Column.class).updatable()) {
                continue;
            }
            updateRowMap.put(pd.getName(), bw.getPropertyValue(pd.getName()));
        }
        boolean flag = updateById(attachmentTag.getId(), updateRowMap);
        //如果需要大于1时，抛出异常并回滚，需要在这里修改
        return flag;
    }
    
    /**
     * 根据id删除AttachmentTag实例
     * 1、如果入参数为空，则抛出异常
     * 2、执行删除后，将返回数据库中被影响的条数 > 0，则返回true
     *
     * @param id
     * @return boolean 删除的条数>0则为true [返回类型说明]
     * @exception throws 
     * @see [类、类#方法、类#成员]
     */
    @Transactional
    public boolean moveToHisByAttachmentId(String attachmentId) {
        AssertUtils.notEmpty(attachmentId, "attachmentId is empty.");
        
        AttachmentTag condition = new AttachmentTag();
        condition.setAttachmentId(attachmentId);
        
        this.attachmentTagDao.copyToHis(condition);
        this.attachmentTagDao.delete(condition);
        //这里就不再判断删除了多少条了，避免没有关联的tag
        return true;
    }
}
